package net.ib.mtalk.ui.attachment.vcard;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Im;
import android.provider.ContactsContract.CommonDataKinds.Organization;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;

/**
 * vCardStr 값을 ContactStruct 객체로 변환해준다.
 * 
 * @author happy2v
 * @since : 2011-02-22
 * @history : 2011-05-17 리팩토링
 * 
 * @version 0.2.2
 *
 */
public class VCardParser {
	
	// 버전을 나타내는 상수.
	public final static int VERSION_VCARD21_INT = 1;
	public final static int VERSION_VCARD30_INT = 2;
	public final static int VERSION_VCARD40_INT = 3;
	
	// 메소드 타입?
	public static final int METHOD_TYPE_BDAY 		= 8;
	public static final int METHOD_TYPE_ANNIVERSARY = 9;
	public static final int METHOD_TYPE_WEBSITE 	= 10;
	public static final int METHOD_TYPE_OTHER 		= 11;
	
	/**
	 *  메소드별 타입 맵
	 */
	private static final HashMap<String, Integer> phoneTypeMap = new HashMap<String, Integer>();
	private static final HashMap<String, Integer> emailTypeMap = new HashMap<String, Integer>();
	private static final HashMap<String, Integer> postalTypeMap = new HashMap<String, Integer>();
	private static final HashMap<String, Integer> imTypeMap = new HashMap<String, Integer>();
	private static final HashMap<String, Integer> imProtocolMap = new HashMap<String, Integer>();
	private static final HashMap<String, Integer> organizationTypeMap = new HashMap<String, Integer>();
	private static final HashMap<String, Integer> methodTypeMap = new HashMap<String, Integer>();
	
	static{
		phoneTypeMap.put("HOME", Phone.TYPE_HOME);
        phoneTypeMap.put("CELL", Phone.TYPE_MOBILE);
        phoneTypeMap.put("WORK", Phone.TYPE_WORK);
        phoneTypeMap.put("WORK-FAX", Phone.TYPE_FAX_WORK);
        phoneTypeMap.put("HOME-FAX", Phone.TYPE_FAX_HOME);
        phoneTypeMap.put("PAGER", Phone.TYPE_PAGER);
        phoneTypeMap.put("OTHER", Phone.TYPE_OTHER);
        phoneTypeMap.put("CALLBACK", Phone.TYPE_CALLBACK);
        phoneTypeMap.put("CAR", Phone.TYPE_CAR);
        phoneTypeMap.put("COMPANY_MAIN", Phone.TYPE_COMPANY_MAIN);
        phoneTypeMap.put("ISDN", Phone.TYPE_ISDN);
        phoneTypeMap.put("MAIN", Phone.TYPE_MAIN);
        phoneTypeMap.put("OTHER_FAX", Phone.TYPE_OTHER_FAX);
        phoneTypeMap.put("RADIO", Phone.TYPE_RADIO);
        phoneTypeMap.put("TELEX", Phone.TYPE_TELEX);
        phoneTypeMap.put("TTY_TDD", Phone.TYPE_TTY_TDD);
        phoneTypeMap.put("WORK_MOBILE", Phone.TYPE_WORK_MOBILE);
        phoneTypeMap.put("WORK_PAGER", Phone.TYPE_WORK_PAGER);
        phoneTypeMap.put("ASSISTANT", Phone.TYPE_ASSISTANT);
        phoneTypeMap.put("MMS", Phone.TYPE_MMS);
        
        emailTypeMap.put("HOME", Email.TYPE_HOME);
        emailTypeMap.put("WORK", Email.TYPE_WORK);
        emailTypeMap.put("OTHER", Email.TYPE_OTHER);
        emailTypeMap.put("MOBILE", Email.TYPE_MOBILE);
        
        postalTypeMap.put("HOME", StructuredPostal.TYPE_HOME);
        postalTypeMap.put("WORK", StructuredPostal.TYPE_WORK);
        postalTypeMap.put("OTHER", StructuredPostal.TYPE_OTHER);
        
        imTypeMap.put("HOME", Im.TYPE_HOME);		
        imTypeMap.put("OTHER", Im.TYPE_OTHER);		
        imTypeMap.put("WORK", Im.TYPE_WORK);		
        
        imProtocolMap.put("AIM", Im.PROTOCOL_AIM);
        imProtocolMap.put("GOOGLE_TALK", Im.PROTOCOL_GOOGLE_TALK);
        imProtocolMap.put("ICQ", Im.PROTOCOL_ICQ);
        imProtocolMap.put("JABBER", Im.PROTOCOL_JABBER);
        imProtocolMap.put("MSN", Im.PROTOCOL_MSN);
        imProtocolMap.put("NETMEETING", Im.PROTOCOL_NETMEETING);
        imProtocolMap.put("QQ", Im.PROTOCOL_QQ);
        imProtocolMap.put("SKYPE", Im.PROTOCOL_SKYPE);
        imProtocolMap.put("YAHOO", Im.PROTOCOL_YAHOO);
        
        organizationTypeMap.put("OTHER", Organization.TYPE_OTHER);
        organizationTypeMap.put("WORK", Organization.TYPE_WORK);
        
        methodTypeMap.put("OTHER", METHOD_TYPE_OTHER);
        methodTypeMap.put("BDAY", METHOD_TYPE_BDAY);
        methodTypeMap.put("ANNIVERSARY", METHOD_TYPE_ANNIVERSARY);
        methodTypeMap.put("WEBSITE", METHOD_TYPE_WEBSITE);
	}
	
	ContactStruct vCardStruct;
	String vCardData;
	
	int start = 0;
	int end = 0;
	char ch;
	
	public VCardParser(){
		vCardStruct = new ContactStruct();
	}
	
	public ContactStruct parse(String vCardStr){
		vCardData = vCardStr;
		
		int start = 0;
		char ch;
		
		List<String> lineData = new ArrayList<String>();
		
		// 한줄씩 나눠 담는다.
		for(int i = 0; i < vCardData.length(); i++){
			ch = vCardData.charAt(i);
			if (ch == '\n') {
				lineData.add(vCardData.substring(start, i));
				start = i + 1;
			}
		}

		// 한줄의 데이터를 저장하는 변수 
		String lineStr;
		// 한줄씩 읽는다.
		for(String line : lineData){
			lineStr = line;
			// 한줄의 데이터를 처리하자!
			for(int i = 0; i < lineStr.length(); i++){
				ch = lineStr.charAt(i);
				if(ch == ':'){ // ':' 올만한 녀석들을 정리해보자!
					start = i + 1;
					// 마지막이면 종료해버리자!
					if(lineStr.substring(0, i).equals("END")){
						break;
//					}else if(lineStr.substring(0, i).equals("N")){ // 넌 하지 말자!
//						namePaser(lineStr, start);
					}else if(lineStr.substring(0, i).equals("FN")){
						vCardStruct.name = vCardStruct.fullName = lineStr.substring(start, lineStr.length());
						break;
					}else if(lineStr.substring(0, i).equals("NICKNAME")){
						break;
					}else if(lineStr.substring(0, i).equals("BDAY")){
						break;						
					}else if(lineStr.substring(0, i).equals("LABEL")){
						break;
					}else if(lineStr.substring(0, i).equals("MAILER")){
						break;
					}else if(lineStr.substring(0, i).equals("TZ")){
						break;
					}else if(lineStr.substring(0, i).equals("GEO")){
						break;
					}else if(lineStr.substring(0, i).equals("TITLE")){
						vCardStruct.title = lineStr.substring(start, lineStr.length());
						break;
					}else if(lineStr.substring(0, i).equals("ROLE")){
						break;
					}else if(lineStr.substring(0, i).equals("LOGO")){
						break;
					}else if(lineStr.substring(0, i).equals("AGENT")){
						break;
					}else if(lineStr.substring(0, i).equals("ORG")){
						vCardStruct.company = lineStr.substring(start, lineStr.length());
						break;
					}else if(lineStr.substring(0, i).equals("NOTE")){
						vCardStruct.addNote(lineStr.substring(start, lineStr.length()), true);
						break;
					}else if(lineStr.substring(0, i).equals("KEY")){
						break;
					}else if(lineStr.substring(0, i).equals("REV")){
						break;
					}else if(lineStr.substring(0, i).equals("SOUND")){
						break;
					}else if(lineStr.substring(0, i).equals("URL")){
						break;
					}else if(lineStr.substring(0, i).equals("UID")){
						break;
					}else if(lineStr.substring(0, i).equals("VERSION")){
						break;
					}
				}
				if(ch == ';'){ // ';' 타입이나 옵션이 있는 경우.
					start = i + 1;
					if(lineStr.substring(0, i).equals("PHOTO")){
						break;
					}else if(lineStr.substring(0, i).equals("ADR")){
						adrParser(lineStr, start);
						break;						
					}else if(lineStr.substring(0, i).equals("TEL")){
						telParser(lineStr, start);
						break;
					}else if(lineStr.substring(0, i).equals("EMAIL")){
						emailParser(lineStr, start);
						break;
					}else if(lineStr.substring(0, i).equals("IMPP")){
						imParser(lineStr, start);
						break;
					}else{
						break;
					}
				}
			}
		}
		
		return vCardStruct;
	}
	
	/**
	 * 전화번호를 파싱해서  ContactStruct에 저장
	 * @param str
	 * @param start
	 */
	private void telParser(String str, int start){
		int index = str.indexOf("TYPE=")+5;
		if(index == -1){
			index = start;
		}
		int seperate = str.indexOf(':');
		String typeList = str.substring(index, seperate);
		String content = str.substring(seperate+1, str.length());
		String type;
		
		// ContactStruct 에 들어갈 값
		int typeInt;
		String label;
		
		// 타입을 나누어서 저장한다.
		while(true){
			index = typeList.indexOf(',');
			if(index != -1){
				// 타입을 설정한다.
				type = typeList.substring(0, index);
				if(phoneTypeMap.containsKey(type)){
					typeInt = phoneTypeMap.get(type);
					label = null;
				}else{
					typeInt = Phone.TYPE_CUSTOM;
					label = type.replaceFirst("CUSTOM-", "");;
				}
				// 전화번호 리스트에 추가한다.
				vCardStruct.addPhone(typeInt, content, label, true);
				typeList = typeList.substring(index+1, typeList.length());
			}else{
				type = typeList.substring(0, typeList.length());
				if(phoneTypeMap.containsKey(type)){
					typeInt = phoneTypeMap.get(type);
					label = null;
				}else{
					typeInt = Phone.TYPE_CUSTOM;
					label = type.replaceFirst("CUSTOM-", "");;
				}
				// 전화번호 리스트에 추가한다.
				vCardStruct.addPhone(typeInt, content, label, true);
				break;
			}
		}
	}
	
	/**
	 * 이메일을 파싱해서  ContactStruct에 저장
	 * @param str
	 * @param start
	 */
	private void emailParser(String str, int start){
		int index = str.indexOf("TYPE=")+5;
		if(index == -1){
			index = start;
		}
		int seperate = str.indexOf(':');
		String typeList = str.substring(index, seperate);
		String content = str.substring(seperate+1, str.length());
		String type;
		
		// ContactStruct 에 들어갈 값
		int typeInt;
		String label;
		
		// 타입을 나누어서 저장한다.
		while(true){
			index = typeList.indexOf(',');
			if(index != -1){
				// 타입을 설정한다.
				type = typeList.substring(0, index);
				if(emailTypeMap.containsKey(type)){
					typeInt = emailTypeMap.get(type);
					label = null;
				}else{
					typeInt = Email.TYPE_CUSTOM;
					label = type.replaceFirst("CUSTOM-", "");
				}
				// 이메일 리스트에 추가한다.
				vCardStruct.addEmail(typeInt, content, label, true);
				typeList = typeList.substring(index+1, typeList.length());
			}else{
				type = typeList.substring(0, typeList.length());
				if(emailTypeMap.containsKey(type)){
					typeInt = emailTypeMap.get(type);
					label = null;
				}else{
					typeInt = Email.TYPE_CUSTOM;
					label = type.replaceFirst("CUSTOM-", "");;
				}
				// 이메일 리스트에 추가한다.
				vCardStruct.addEmail(typeInt, content, label, true);
				break;
			}
		}
	}
	
	/**
	 * 주소를 파싱해서 ContactStruct에 저장
	 * 한줄의 문자열과 ';' 다음 시작점을 알려준다.
	 * @param str
	 * @param start
	 */
	private void adrParser(String str, int start){
		int index = str.indexOf("TYPE=")+5;
		if(index == -1){
			index = start;
		}
		int seperate = str.indexOf(':');
		String typeList = str.substring(index, seperate);
		String content = str.substring(seperate+1, str.length());
		String type;
		
		// ContactStruct 에 들어갈 값
		int typeInt;
		String label;
		
		// 타입을 나누어서 저장한다.
		while(true){
			index = typeList.indexOf(',');
			if(index != -1){
				// 타입을 설정한다.
				type = typeList.substring(0, index);
				if(postalTypeMap.containsKey(type)){
					typeInt = postalTypeMap.get(type);
					label = null;
				}else{
					typeInt = StructuredPostal.TYPE_CUSTOM;
					label = type.replaceFirst("CUSTOM-", "");;
				}
				// 주소록을 추가한다.
				vCardStruct.addPostal(typeInt, getPostalValueList(content), 
						label, getPostalFormattedAddress(content), true);
				typeList = typeList.substring(index+1, typeList.length());
			}else{
				type = typeList.substring(0, typeList.length());
				if(postalTypeMap.containsKey(type)){
					typeInt = postalTypeMap.get(type);
					label = null;
				}else{
					typeInt = StructuredPostal.TYPE_CUSTOM;
					label = type.replaceFirst("CUSTOM-", "");;
				}
				// 주소록을 추가한다.
				vCardStruct.addPostal(typeInt, getPostalValueList(content), 
						label, getPostalFormattedAddress(content), true);
				break;
			}
		}
	}
	
	// 주소록에 들어가는 아이템 리스트를 만든다.
	private List<String> getPostalValueList(String str){
		List<String> postalValueList = new ArrayList<String>();
		String data = str;
		int index;
		
		while(true){
			index = data.indexOf(';');
			if(index != -1){
				postalValueList.add(data.substring(0, index));
				data = data.substring(index+1, data.length());
			}else{
				postalValueList.add(data.substring(0, data.length()));
				break;
			}
		}
		return postalValueList;
	}
	
	// 형식화된 주소를 만든다.
	private String getPostalFormattedAddress(String str){
		String formattedAddress = "";
		String data = str;
		int index;
		
		while(true){
			index = data.indexOf(';');
			if(index != -1){
				formattedAddress = formattedAddress + data.substring(0, index) + " ";
				data = data.substring(index+1, data.length());
			}else{
				formattedAddress = formattedAddress + data.substring(0, data.length());
				break;
			}
		}
		return formattedAddress;
	}
	
	/**
	 * 메신져를 파싱해서 ContactStruct에 저장
	 * @param str
	 * @param start
	 */
	private void imParser(String str, int start){
		int index = str.indexOf("TYPE=")+5;
		if(index == -1){
			index = start;
		}
		int seperate = str.indexOf(':');
		String typeList = str.substring(index, seperate);
		String content = str.substring(seperate+1, str.length());
		String type;
		String protocol;
		
		// ContactStruct 에 들어갈 값
		int typeInt;
		int protocolInt;
		String customProtocol;
		String label;
		
		// 타입을 나누어서 저장한다.
		while(true){
			index = typeList.indexOf(',');
			if(index != -1){
				// 프로토콜을 설정한다.
				protocol = typeList.substring(0, index);
				type = typeList.substring(0, index);
				if(imProtocolMap.containsKey(protocol)){
					protocolInt = imProtocolMap.get(protocol);
					customProtocol = null;
				}else{
					protocolInt = Im.PROTOCOL_CUSTOM;
					customProtocol = protocol.replaceFirst("CUSTOM-", "");;
				}
				// 타입을 설정한다.
				if(imTypeMap.containsKey(type)){
					typeInt = imTypeMap.get(type);
					label = null;
				}else{
					typeInt = Im.TYPE_CUSTOM;
					label = type.replaceFirst("CUSTOM-", "");;
				}
				// 메신져를 추가한다.
				vCardStruct.addImData(protocolInt, customProtocol, typeInt, content, label, true);
				typeList = typeList.substring(index+1, typeList.length());
			}else{
				protocol = typeList.substring(0, typeList.length());
				type = typeList.substring(0, typeList.length());
				if(imProtocolMap.containsKey(protocol)){
					protocolInt = imProtocolMap.get(protocol);
					customProtocol = null;
				}else{
					protocolInt = Im.PROTOCOL_CUSTOM;
					customProtocol = protocol.replaceFirst("CUSTOM-", "");;
				}
				// 타입을 설정한다.
				if(imTypeMap.containsKey(type)){
					typeInt = imTypeMap.get(type);
					label = null;
				}else{
					typeInt = Im.TYPE_CUSTOM;
					label = type.replaceFirst("CUSTOM-", "");;
				}
				// 메신져를 추가한다.
				vCardStruct.addImData(protocolInt, customProtocol, typeInt, content, label, true);
				break;
			}
		}
	}
}